package com.siyue.controller;

import com.siyue.service.ActiveService;
import com.siyue.service.UserActionService;
import com.siyue.util.RedisUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/")
public class 点赞_Controller {

    @Autowired
    private ActiveService activeService;
    @Autowired
    private UserActionService userActionService;

    /**
     * 点赞、取消赞(单个服务下保证线程安全  使用synchronized)
     */
    @GetMapping("/praise")
    public String test1(Integer userId, Integer activeId) throws InterruptedException {
        String userAction = null;
        //解决线程安全问题
        synchronized (this) {
            userAction = userActionService.praise(userId, activeId);
        }
        return userAction;
    }

    /**
     * 点赞、取消赞(单个服务下保证线程安全  使用sql锁)
     */
    @GetMapping("/praise-lock-sql")
    public String test1LockOnSQL(Integer userId, Integer activeId) throws InterruptedException {
        String userAction = null;
        //解决线程安全问题
        userAction = userActionService.praiseLockWithSQL(userId, activeId);
        return userAction;
    }


    @Autowired
    private RedisUtil redisUtil;

    /**
     * 点赞、取消赞(分布式服务下  使用redis分布式锁)
     */
    @GetMapping("/praise-redis-lock")
    @Transactional
    public String test2(Integer userId, Integer activeId) throws InterruptedException {
        String userAction = null;
        String PRAISE_LOCK = "active_praise_lock" + "-" + userId;
        // 每个人进来先要进行加锁，key值为"good_lock"
//        String value = UUID.randomUUID().toString().replace("-","");
        boolean flag = redisUtil.setnxWithEx(PRAISE_LOCK, userId, 10, TimeUnit.SECONDS);
        //加锁失败
        if (!flag) {
            return userId + ",抢锁失败！";
        }
        try {
            userAction = userActionService.praise1(userId, activeId);
        } catch (Exception e) {

        } finally {
            redisUtil.del(PRAISE_LOCK);
        }
        return userAction;
    }

    /**
     * 点赞、取消赞(分布式服务下  使用redis分布式锁 (Redisson))
     * Redission执行流程如下：（只要线程一加锁成功，就会启动一个watch dog看门狗，它是一个后台线程，
     * 会每隔10秒检查一下（锁续命周期就是设置的超时时间的三分之一），如果线程还持有锁，就会不断的延长锁key的生存时间。
     * 因此，Redis就是使用Redisson解决了锁过期释放，业务没执行完问题。当业务执行完，释放锁后，再关闭守护线程，
     *
     */

    /**
     * 直接注入RedissonClient就可以直接使用.
     */
    @Resource
    private RedissonClient redissonClient;

    @GetMapping("/praise-redis-lock1")
    @Transactional
    public String test2RedisLock(Integer userId, Integer activeId) throws InterruptedException {
        String userAction = null;
        String PRAISE_LOCK = "active_praise_lock" + "-" + userId;
        // 每个人进来先要进行加锁，key值为"good_lock"
//        String value = UUID.randomUUID().toString().replace("-","");
        //创建锁
        RLock activeLock = redissonClient.getLock(PRAISE_LOCK);
        //加锁 lock() 如果没有抢到锁会发生自旋
//        activeLock.lock();
        boolean flag = activeLock.tryLock();
        if (!flag) {
            return userId + ",抢锁失败！";
        }

        try {
            userAction = userActionService.praise1(userId, activeId);
        } catch (Exception e) {

        } finally {
            activeLock.unlock();
        }
        return userAction;
    }


}
